home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1992 June: ROMin Holiday / ADC Developer CD (1992-06) (''ROMin Holiday'')_iso / Developer Connection - 06-1992.iso / Development Platforms / Apple II / Essentials / Technical.Notes / IIGS / TN.IIGS.094 < prev    next >
Encoding:
Text File  |  1990-09-21  |  10.4 KB  |  217 lines  |  [TEXT/pdos]

  1. Apple II
  2. Technical Notes
  3. _____________________________________________________________________________
  4.                                                   Developer Technical Support
  5.  
  6. Apple IIgs
  7. #94:    Packing It In (and Out)
  8.  
  9. Written by:    C.K. Haun <TR>                                  September 1990
  10.  
  11. This Technical Note discusses a potential problem with the Miscellaneous Tools 
  12. routine UnPackBytes.
  13. _____________________________________________________________________________
  14.  
  15. PackBytes and UnPackBytes are handy data compression and expansion routines 
  16. built into the Apple IIgs System Software.  Using them can dramatically reduce 
  17. the amount of space your application uses on disk or in memory, but you need 
  18. to understand how these calls work to avoid problems in your applications.
  19.  
  20.  
  21. Buffer Size, Buffer Size, Buff, Buff, Buffer Size
  22.  
  23. There are some situations where the Miscellaneous Tools call UnPackBytes does 
  24. not function as expected and can cause your application to loop infinitely 
  25. while you're waiting for an unpacking process to finish.
  26.  
  27. The following packed data and code (in APW assembly) demonstrates the problem.  
  28. It shows a small routine that unpacks data in two steps, simulating the 
  29. situation in many applications where an arbitrary amount of data is unpacked 
  30. in a variable amount of unpacking actions, depending on the results of the 
  31. last unpack pass.
  32.  
  33. UnPackBuffer     ds    160                     ; area to unpack the data to
  34. UnPackBufferPtr  dc    i4'UnPackBuffer'        ; pointer to unpacking buffer
  35. UnPackBufferSize ds    2
  36. temp             ds    2
  37.  
  38. PackedData       dc h'FFFFFFFF'
  39. EndPackData      anop
  40. PackLength       dc i2'EndPackData-PackedData' ; how many bytes of packed data
  41.  
  42. * In packbytes format $FFFF means '64 repeats of the next byte ($FF) taken as 
  43. * 4 bytes' as described on page 14-39 of Toolbox Reference, so
  44. * this data should unpack into 512 $FF bytes
  45.  
  46. * The following code loops infinitely
  47.  
  48.                   lda   #160                    ; Unpack buffer size
  49.                   sta   UnPackBufferSize
  50. UnPackLoop        pea   0                       ; return space
  51.                   pushlong #PackedData          ; pointer to packed data
  52.                   pea   2                       ; size of the packed data, 
  53. ;                                                 unpack two bytes
  54.                                                 ; at a time
  55.                   pushlong #UnPackBufferPtr     ; pointer to pointer to 
  56. ;                                                 unpacking buffer
  57.                   pushlong #UnPackBufferSize    ; pointer to word with the 
  58. ;                                                 size of the unpacking buffer
  59.                   _UnPackBytes
  60.                   pla                           ; returns 0 bytes unpacked
  61.                   sta   temp
  62.                   lda   PackLength
  63.                   sec
  64.                   sbc   temp                    ; subtracting it from our 
  65. ;                                                 known
  66.                   sta   PackLength              ; length of packed data
  67.                   bne   UnPackLoop              ; this is always be non-zero
  68.  
  69. The problem is in the data and the buffer size.  UnPackBytes is being told to 
  70. unpack two bytes ($FFFF), which generate 256 bytes of unpacked data, into a 
  71. 160-byte buffer.  Instead of reporting an error with this condition, 
  72. UnPackBytes instead just does nothing and passes back zero as the returned 
  73. number of bytes unpacked.  If you are relying on the unpacked byte count 
  74. returned to control your unpacking loop, then you may encounter this problem.
  75.  
  76. UnPackBytes can be used to unpack in multiple steps, of course, but it cannot 
  77. unpack a partial record.  It cannot unpack 160 bytes of the 256 bytes 
  78. specified in this record because UnPackBytes does not maintain any state 
  79. information, so it must unpack full records or do nothing.  If the buffer had 
  80. been 256 bytes, this call would have succeeded.
  81.  
  82.  
  83. The Fix
  84.  
  85. Fortunately, it's easy to avoid this situation if  you know that it can exist.  
  86. Simply, always supply UnPackBytes with a buffer that is big enough for it to 
  87. unpack at least two bytes (a flag or count byte and a data byte).  The largest 
  88. value of a flag or count word possible is $FF, 64 repeats of the next byte 
  89. taken as four bytes, which generates 256 unpacked bytes.  So always give 
  90. UnPackBytes a 256-byte long output buffer and you should never encounter this 
  91. problem.
  92.  
  93.  
  94. Check Your Current Applications
  95.  
  96. Please check your current applications to see if you could encounter this 
  97. problem.  One of the most likely places for this error to occur is in 
  98. applications that process Apple Preferred (file type $C0, auxiliary type 
  99. $0002) pictures.  While most pictures currently available are screen-width or 
  100. less (160 bytes or less per scan line), the Apple Preferred format and 
  101. QuickDraw II both support pictures that are wider than the current Apple IIgs 
  102. screen.  If someone has created a picture with a PixelsPerScanLine value of 
  103. 1,280 with a ModeWord of $0080, it would generate a scan line that was 320 
  104. bytes long.  If a scan line in this hypothetical picture were all white, for 
  105. example, the first two bytes of the packed scan line would be $FFFF, and 
  106. applications that assume a standard maximum 160 bytes per scan line would not 
  107. handle this correctly.
  108.  
  109.  
  110. But That's Not All...
  111.  
  112. UnPackBytes has some other buffering problems of which you need to be aware.  
  113. The size and location of the input buffer (the buffer containing your packed 
  114. data) can also cause problems.
  115.  
  116. Note:  These problems only occur if you are doing multipass unpacks.  If 
  117.        you always unpack a packed data range in one pass (with one call 
  118.        to UnPackBytes for the whole data set) then you are not affected 
  119.        by these problems, and the restrictions described herein do not 
  120.        apply.
  121.  
  122. Multipass Restrictions
  123.  
  124. When performing a multipass unpack (as described on pp. 14-43..44 of the Apple 
  125. IIgs Toolbox Reference, Volume 1) the packed data needs to follow two rules.
  126.  
  127. Rule 1:  Your packed data buffer cannot cross a bank boundary.
  128. Rule 2:  Your packed data buffer needs to be at least 65 bytes longer 
  129.          than the actual size of the data.
  130.  
  131. These rules are required by a bug in UnPackBytes.  When UnPackBytes begins to 
  132. unpack a record, it checks the record data to see if there are enough bytes in 
  133. the current source buffer to unpack the number of bytes requested in the 
  134. record header (described on pg. 14-39 of the Apple IIgs Toolbox Reference, 
  135. Volume 1).  If there are not enough bytes left for the current record (i.e., 
  136. the header says to process 63 bytes, and there are only 30 left in the 
  137. buffer), UnPackBytes returns to the caller.  The caller then adjusts the 
  138. source buffer for the next pass based on the amount of actual bytes unpacked, 
  139. so the bytes left over from the last pass get processed the next time.
  140.  
  141. The problem occurs when the partial record is close to the end of a bank.  
  142. When UnPackBytes checks to see if there is enough data left in the buffer, the 
  143. check is flawed when the real end of the buffer is near the end of a bank, and 
  144. a complete copy of the partial record would extend into the next bank.  
  145. UnPackBytes erroneously thinks that the record is complete, and happily 
  146. unpacks the remaining actual packed data, plus random information from the 
  147. next bank.  It continues to unpack nonsense data until it fills the unpacking 
  148. buffer and the number of bytes unpacked returned by the UnPackBytes call is 
  149. greater than the bufferSize parameter passed as input.
  150.  
  151. To prevent this bug from occurring, you need to make sure that the buffer for 
  152. the packed data is at least one record length away from the end of a memory 
  153. bank.  Since the largest packed data record is one flag byte and 64 data 
  154. bytes, adding 65 bytes to the end of your buffer does the trick.  This ensures 
  155. that your packed data is 65 bytes away from the end.
  156.  
  157. Following is an example of a safe way to prepare your packed data buffer for 
  158. multipass unpacking, in APW assembly:
  159.  
  160. * Some data space
  161. myCallBlock  dc     i2'2'          ; two parameters
  162. fileRefNum   ds     2              ; file reference number
  163. EOFreturned  ds     4              ; file length returned by this call
  164. myIDNumber   ds     2              ; your application memory manager ID number
  165. * assume that a packed data file is open, and it's a plain packed screen 
  166. * image, not over 32K
  167.              jsl    $E100A8              ; ask GS/OS for the length of the 
  168. data
  169.              dc     i2'$2019'            ; Get_EOF call
  170.              dc     i4'myCallBlock'
  171.  
  172. * Now we need a handle to read it into
  173.              pha
  174.              pha                         ; return space
  175.              pea    0                    ; size, high word
  176.              lda    EOFreturned          ; the actual size of the packed data
  177.              sta    actualPackDataSize
  178.              clc
  179.              adc    #65                  ; ask for a handle 65 bytes longer 
  180. ;                                          than the data
  181.              pha
  182.              lda    myIDnumber           ; Memory Manager ID for your 
  183. ;                                          application
  184.              pha
  185.              pea    $8010                ; attrLocked and attrNoCross
  186.              pea    0
  187.              pea    0                    ; anywhere
  188.              _NewHandle                  ; get the handle
  189.  
  190. Now you have a handle 65 bytes longer than your data that does not cross a 
  191. bank boundary.  You are ready to read in the data and perform a multipass 
  192. unpack.
  193.  
  194.  
  195. PackBytes Buffers Count Too
  196.  
  197. PackBytes can also cause you problems if you do not plan for the worst-case 
  198. situation.  Unlike the other toolbox compression routine ACECompress, 
  199. PackBytes is not guaranteed to shrink the source data.  In fact, your data 
  200. size may actually grow after a PackBytes call.
  201.  
  202. If you pass a data stream of 64 bytes, all with different values, to 
  203. PackBytes, PackBytes puts 65 bytes in your output buffer--the 64 original data 
  204. bytes and the flag byte of $3F, indicating "64 bytes follow, all different."  
  205. Unless you preprocess or analyze your data before packing to avoid this 
  206. situation, make sure your output buffer is large enough to hold the worst case 
  207. situation, one additional byte generated for every 64 bytes passed to 
  208. PackBytes for compression.
  209.  
  210.  
  211. Further Reference
  212. _____________________________________________________________________________
  213.   o  Apple IIgs Toolbox Reference, Volumes 1-3
  214.   o  File Type Note for File Type $C0, Auxiliary Type $0002, Apple Preferred 
  215.      Format
  216.  
  217.